package cn.yunyichina.provider.pay.service.impl;

import cn.yunyichina.provider.framework.dubbo.service.AlipayService;
import cn.yunyichina.provider.framework.dubbo.service.BaseService;
import cn.yunyichina.provider.framework.exception.CallException;
import cn.yunyichina.provider.framework.qiniu.QiniuService;
import cn.yunyichina.provider.framework.utils.HttpUtils;
import cn.yunyichina.provider.framework.utils.UUIDUtil;
import cn.yunyichina.provider.iface.entity.base.EventVo;
import cn.yunyichina.provider.iface.entity.base.LogVo;
import cn.yunyichina.provider.iface.entity.common.Response;
import cn.yunyichina.provider.pay.config.Alipay;
import cn.yunyichina.provider.pay.config.Config;
import cn.yunyichina.provider.pay.constant.MethodRouter;
import cn.yunyichina.provider.pay.dao.OrderCheckedExceptionDao;
import cn.yunyichina.provider.pay.dao.PaymentCheckSourceFileDao;
import cn.yunyichina.provider.pay.entity.OrderCheckedException;
import cn.yunyichina.provider.pay.entity.PaymentCheckSourceFile;
import cn.yunyichina.provider.pay.service.AlipayPaymentService;
import cn.yunyichina.provider.pay.service.FinanceService;
import cn.yunyichina.provider.pay.utils.AlipayCSVFileUtil;
import cn.yunyichina.utils.convert.JsonUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 对账文件数据解析入库
 * Created by JoeZ on 2016/10/19.
 */
@Service
public class AlipayPaymentServiceImpl implements AlipayPaymentService {

    private static Logger logger = LoggerFactory.getLogger(AlipayPaymentServiceImpl.class);

    @Resource
    private PaymentCheckSourceFileDao paymentCheckSourceFileDao;

    @Resource
    private OrderCheckedExceptionDao orderCheckedExceptionDao;
    
    @Resource
    private FinanceService financeService;

    @Resource
    private Properties yaml;

    SimpleDateFormat YYYYMMDDHHMISS = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    SimpleDateFormat YYYYMMDDHHMISS14 = new SimpleDateFormat("yyyyMMddHHmmss");

    
    /**
     * 解析本地对账文件
     *
     * @return stop_finance_flag 是否需要停止对账,full_success是否完全成功,count成功入库的记录数,import_full_success导入是否成功
     */
    @Override
    public Response getAlipayPayment(String json) {
        Response response = new Response();
        Map<String,String> jsonMap = JsonUtils.parseObject(json,Map.class);
        JSONObject mapReturn = new JSONObject();
        mapReturn.put("error_message", "");
        
        String appId = jsonMap.get("appId");
        String hospitalId = jsonMap.get("orgId");
        String hospitalName = jsonMap.get("orgName");
        String tag = jsonMap.get("tag");
        String date = jsonMap.get("date");
        
        mapReturn.put("org_id", hospitalId);
        mapReturn.put("app_id", appId);
        mapReturn.put("date", date);
        
        
        String fileName = "";
        
        
        //是否记录系统日志
    	boolean saveLogFlag = false;
    	LogVo log = new LogVo();
		log.setOrgId(hospitalId);
		log.setOrgName(hospitalName);
		
		boolean importFullSuccess = false;
        boolean saveDbSuccess = false;
        String message = "";
        
        //调用alipay子系统
        response = AlipayService.callHumpFromInternal(MethodRouter.ALIPAY_DOWNLOAD_FILE_PATH, JSON.toJSONString(jsonMap));
        logger.info("文件下载信息："+JsonUtils.toJsonString(response));
        if ("0".equals(response.getResultCode())) {
            fileName = response.getResult();
            if (StringUtils.isNotBlank(fileName)) {

                //从七牛获取文件到本地
                String bucketURL = yaml.getProperty(Alipay.QINIU_CHECK_ACCTOUNT_DOWNLOAD_URL);
                String path = yaml.getProperty(Config.CONFIG_PAY_ALIPAY_CHECK_ACCOUNT_PATH);
                String url = QiniuService.download(fileName, path, bucketURL);

                String filePath = path + fileName;
                logger.info(hospitalName + "---yaml property bucketURL:" + bucketURL + ",path:" + path);
                logger.info(hospitalName + "---Check_Account_File_Save_Path:" + filePath);
                if (StringUtils.isNotBlank(url)) {
                    logger.info(hospitalName + "---Ready to start download checkAccountFile and save datas..");
                    boolean flag=false;
                    int count=0;
                    int repeatCount=5;
                    while (!flag){
                        flag = HttpUtils.httpDownload(url, filePath);
                        count++;
                        if(count>repeatCount){
                            break;
                        }
                    }

                    if (flag) {
                        try {
                            mapReturn = paymentCheckSourceBillFileDataSave(filePath, hospitalId, hospitalName, appId, tag);
                            mapReturn.remove("list");
                            
                            
                            if (mapReturn.containsKey("import_full_success") && mapReturn.getBooleanValue("import_full_success")) {
                            	message = "导入第三方数据成功";
                            	importFullSuccess = true;
                            }
                            else if (mapReturn.containsKey("import_full_success") && mapReturn.getBooleanValue("import_full_success") == false) {
                            	message = "导入第三方数据存在异常";
                            	importFullSuccess = false;
                            }
                            if (mapReturn.containsKey("stop_finance_flag") && mapReturn.getBooleanValue("stop_finance_flag")) {
                        		message += " 订单号 不存在，终止对账";
                        		
                        		log.setContent(message);
                        		saveLogFlag = true;
                        		
                        		//回退数据,暂不执行，因为调用方会回退
//                        		try {
//									JSONObject paramCheck = new JSONObject();
//									paramCheck.put("org_id",hospitalId);
//									paramCheck.put("begin_pay_date", date);
//									paramCheck.put("end_pay_date", date);
//									paramCheck.put("clear_flag", 1);
//									financeService.resetFinanceSettingBill(JsonUtils.toJsonString(paramCheck));
//								} catch (Exception e) {
//									logger.error("回退数据失败"+json,e);
//								}
                        		
                        	}
                            if ( ! mapReturn.containsKey("count")) {
                            	message += " 没有执行入库操作,可能存在异常，或没有可入库的数据";
                            	saveDbSuccess = false;
                            }
                            else if (mapReturn.containsKey("count") && mapReturn.getIntValue("count") == 0) {
                        		message += " 第三方数据入库失败";
                        		saveDbSuccess = false;
                        		
                        		log.setContent(message);
                        		saveLogFlag = true;
                        	}
                            else if (mapReturn.containsKey("count") && mapReturn.getIntValue("count") > 0) {
                        		message += " 第三方数据入库成功";
                        		log.setContent(message);
                        		saveDbSuccess = true;
                        		
                        	}
                            if (mapReturn.containsKey("exception_flag") && mapReturn.getBooleanValue("exception_flag")) {
                            	log.setContent("处理过程发生异常");
                            	saveLogFlag = true;
                            }
                            
                            String resultCode = "-1";
                            if (importFullSuccess && saveDbSuccess) {
                            	message = "导入和处理数据成功";
                            	resultCode = "0";
                            }

                            if(mapReturn.containsKey("alipayCount")&&mapReturn.getIntValue("alipayCount") == 0){
                                message="下载了对账文件，但是支付宝账单记录为0";
                                resultCode="51002";
                                importFullSuccess=true;
                                saveDbSuccess=true;
                            }

                            mapReturn.put("message", message);
                            response.setResultCodeAndMessageAndResult(resultCode , message, JsonUtils.toJsonString(mapReturn));
                            
                        } catch (Exception e) {
                            logger.error("数据导入或入库异常", e);
                            response.setResultCodeAndMessage("-1", "数据导入或入库异常");
                            log.setContent("数据导入或入库异常");
                    		saveLogFlag = true;
                        }
                    } else {
                        logger.error("---下载七牛数据失败..hospitalName:" + hospitalName + " and appId:" + appId);
                        response.setResultCodeAndMessage("-1", "下载七牛数据异常");
                        log.setContent("下载七牛数据异常");
                		saveLogFlag = true;
                    }
                }
                else {
                	logger.error("获取第三方数据的url为空");
                	response.setResultCodeAndMessage("-1", "获取第三方数据的url为空");
                	log.setContent("获取第三方数据的url为空");
            		saveLogFlag = true;
                }
            }
            else {
            	logger.error("获取第三方数据的文件名为空");
            	response.setResultCodeAndMessage("-1", "获取第三方数据的文件名为空");
            	log.setContent("获取第三方数据的文件名为空");
        		saveLogFlag = true;
            }

        } else if ("40004".equals(response.getResultCode()) && "isp.bill_not_exist".equals(response.getResultMessage())) {
        	logger.error("文件下载信息："+response.getResultMessage() + " 支付宝账单不存在");
        	mapReturn.put("error_message", "支付宝账单不存在");
            response.setResultCodeAndMessage("51002" , response.getResultMessage() + " 支付宝账单不存在");
            log.setContent("支付宝账单不存在："+response.getResultMessage() + " 支付宝账单不存在");
            importFullSuccess=true;
            saveDbSuccess=true;
    		//saveLogFlag = true;
        } else {
        	logger.error("文件下载信息："+response.getResultMessage());
        	mapReturn.put("error_message", "文件下载异常");
            response.setResultCodeAndMessage(Response.FAILURE_CODE , response.getResultMessage());
            log.setContent("文件下载异常："+response.getResultMessage());
    		saveLogFlag = true;
        }
        
        mapReturn.put("data_source", "支付宝");

        if (importFullSuccess && saveDbSuccess) {
        	mapReturn.put("full_success", true);
        }
        else {
        	mapReturn.put("full_success", false);
        	Map<String,Object> paramEvent = new HashMap<>();
        	paramEvent.put("event_code", "CK_PULL_PAY_BILL");
        	paramEvent.put("module_code", "CHECK_ACCOUNT");
        	Response responseEvent = BaseService.callHumpFromInternal("yyt.base.event.get", JsonUtils.toJsonString(paramEvent));
        	if (StringUtils.isNotBlank(responseEvent.getResult())) {
        		EventVo event = JsonUtils.parseObject(responseEvent.getResult(), EventVo.class);
        		FinanceServiceImpl.sendSmsForFail(hospitalId,"CK_PULL_PAY_BILL", hospitalName, date, YYYYMMDDHHMISS14.format(new Date()),event.getEventLevel()+"",message);
        	}
        	else {
        		logger.error("获取系统事件定义事事件，无法获取事件级别：CK_PULL_PAY_BILL");
        		FinanceServiceImpl.sendSmsForFail(hospitalId,"CK_PULL_PAY_BILL",hospitalName, date, YYYYMMDDHHMISS14.format(new Date()),"-1","支付宝："+message);
        	}
        	
        	
        	//记录系统日志
            if (saveLogFlag) {
            	FinanceServiceImpl.insertLog(hospitalId,"CK_PULL_PAY_BILL",JsonUtils.toJsonString(mapReturn));
            }
        }
        response.setResult(JsonUtils.toJsonString(mapReturn));
        return response;
    }


    /**
     * 账单入库
     *
     * @param filePath
     * @param hospitalId
     * @param hospitalName
     * @return list List<PaymentCheckSourceFile>,stop_finance_flag 是否需要停止对账,import_full_success是否完全成功,count成功入库的记录数
     */
    @Override
    public JSONObject paymentCheckSourceBillFileDataSave(String filePath, String hospitalId, String hospitalName, String appId, String tag) {
    	JSONObject mapReturn = new JSONObject();
        List<PaymentCheckSourceFile> payDatas = null;
        try {
            if(StringUtils.isNotBlank(tag)){
            	mapReturn = aplipayPartyimportBills(filePath, hospitalId, hospitalName, appId);
            }else{
            	mapReturn = autoAplipayPartyimportBills(filePath, hospitalId, hospitalName, appId);
            	
            }
            logger.info(JsonUtils.toJsonString(mapReturn));
        	payDatas = (List<PaymentCheckSourceFile>) mapReturn.get("list");
        	
        	if (mapReturn.containsKey("stop_finance_flag") && mapReturn.getBooleanValue("stop_finance_flag")) {
        		logger.info("终止对账，入库操作取消");
        		
        	}
        	else {
        		if (payDatas.size() > 0) {
                    int count = addSourceFile(payDatas, hospitalId);
                    mapReturn.put("count", String.valueOf(count));
                } else {
                    mapReturn.put("alipayCount", "0");
                    logger.info("拉取阿里的对账单没有处理成功的对账记录或者对账单为空！" + hospitalName);
                }	
        	}
            
        } 
        catch (Exception e) {
            logger.error("账单入库失败", e);
            mapReturn.put("resultCode", "5001");
            mapReturn.put("resultMessage", e.getMessage());
            mapReturn.put("exception_flag", true);
        }
        return mapReturn;
    }


    /**
     * 第三方账单解析(手动)
     *
     * @param filePath
     * @return list List<PaymentCheckSourceFile>,stop_finance_flag 是否需要停止对账,import_full_success是否完全成功
     */
    public JSONObject aplipayPartyimportBills(String filePath, String hospitalId, String hospitalName, String appId) {
        List<PaymentCheckSourceFile> sourceList = null;

        JSONObject mapReturn = new JSONObject();
        mapReturn.put("hospital_name", hospitalName);
        mapReturn.put("hospital_id", hospitalId);
        mapReturn.put("app_id", appId);
        mapReturn.put("file_path", filePath);
        mapReturn.put("stop_finance_flag", false);
        boolean importFullSuccess = false;
        sourceList = new ArrayList();
        try {
            AlipayCSVFileUtil alipayCSVFileUtil = new AlipayCSVFileUtil(filePath);
            List<List<String>> csvDatas = alipayCSVFileUtil.alipayReadCSVFile();
            long beginTime = new Date().getTime() / 1000;
            logger.info("<<<<< aplipayPartyimportBills.beginTime:" + beginTime);

            for (List<String> datas : csvDatas) {

                //过滤非正常交易状态
                if ("退款".equals(datas.get(2)) || "交易".equals(datas.get(2))) {

                    PaymentCheckSourceFile paymentCheckSourceFile = new PaymentCheckSourceFile();
                    //根据orgId、orderNo查询，platformId、platformName
                    Map<String, String> map = new HashMap<String, String>();
                    map.put("order_no", datas.get(1));
                    Response response = BaseService.callHumpFromInternal(MethodRouter.BASE_FIND_ORDER, JSON.toJSONString(map));
                    if ("0".equals(response.getResultCode())) {
                        map = JsonUtils.parseObject(response.getResult(), Map.class);
                        paymentCheckSourceFile.setPlatformId(map.get("platform_id"));
                        paymentCheckSourceFile.setPlatformName(map.get("platform_name"));
                        paymentCheckSourceFile.setPlatformCode(map.get("platform_code"));
                        paymentCheckSourceFile.setPlatformOrgAppCode(map.get("platform_org_app_code"));
                        paymentCheckSourceFile.setPlatformOrgAppName(map.get("platform_org_app_name"));
                        paymentCheckSourceFile.setOrgId(map.get("org_id"));
                        paymentCheckSourceFile.setOrgName(map.get("org_name"));
                        paymentCheckSourceFile.setOrgCode(map.get("org_code"));

                    } else {
                        //异常订单录入
                        OrderCheckedException orderException = new OrderCheckedException();
                        orderException.setId(UUIDUtil.get32UUID());
                        orderException.setOrderNo(datas.get(1));
                        orderException.setOrgId(hospitalId);
                        orderException.setPayAppId(appId);
                        orderException.setPayTime(StringUtils.isBlank(datas.get(5)) ? null : datas.get(5));
                        orderException.setExceptionType((short) 1);
                        orderException.setExceptionReason(hospitalName + " 订单号：" + datas.get(1) + " 订单不存在！！");
                        orderException.setCreatedBy("三方对账平台");
                        orderException.setCreatedTime(YYYYMMDDHHMISS.format(new Date()));
                        orderCheckedExceptionDao.insert(orderException);
                        logger.error(hospitalName + " 订单号：" + datas.get(1) + " 订单不存在！！");
//                        continue;
                        //平台没有订单，终止对账
                        mapReturn.put("stop_finance_flag", true);
                        throw new CallException("-1","平台没有订单，终止对账，orderNo="+datas.get(1));
                        
                        
                    }

                    paymentCheckSourceFile.setId(UUIDUtil.get32UUID());
                    paymentCheckSourceFile.setPayAppId(appId);
                    paymentCheckSourceFile.setPaymentDealId(datas.get(0));
                    paymentCheckSourceFile.setOrderNo(datas.get(1));
                    paymentCheckSourceFile.setPayStatus(parsePayStatus(datas.get(2)));
                    paymentCheckSourceFile.setPayStatusDesc(datas.get(2));
                    paymentCheckSourceFile.setGoodsName(datas.get(3));
                    paymentCheckSourceFile.setCreatedTime(StringUtils.isBlank(datas.get(4)) ? null : datas.get(4));
                    paymentCheckSourceFile.setPayTime(StringUtils.isBlank(datas.get(5)) ? null : datas.get(5));
                    paymentCheckSourceFile.setAccountName(datas.get(10));
                    paymentCheckSourceFile.setPayAmount(parseAmount(datas.get(12)));
                    paymentCheckSourceFile.setServiceFee(parseAmount(datas.get(22)));
                    paymentCheckSourceFile.setDescription("0.00".equals(datas.get(datas.size() - 1)) ? null : datas.get(datas.size() - 1));
                    paymentCheckSourceFile.setPayMode((short) 2);
                    paymentCheckSourceFile.setImportTime(YYYYMMDDHHMISS.format(new Date()));
                    paymentCheckSourceFile.setUpdateTime(YYYYMMDDHHMISS.format(new Date()));

                    sourceList.add(paymentCheckSourceFile);
                }
            }
            
            importFullSuccess = true;
            logger.info("<<<<< aplipayPartyimportBills.endTime:" + ((new Date().getTime() / 1000) - beginTime));

        } 
        catch (CallException ce) {
        	importFullSuccess = false;
        }
        catch (Exception e) {
        	importFullSuccess = false;
            logger.error("aplipayPartyimportBills:[第三方账单读取失败]", e);
            mapReturn.put("exception_flag", true);
           
        }
        mapReturn.put("import_full_success", importFullSuccess);
        mapReturn.put("list", sourceList);
        return mapReturn;
    }


    /**
     * 第三方账单解析(自动)
     *
     * @param filePath
     * @return list List<PaymentCheckSourceFile>,stop_finance_flag 是否需要停止对账,import_full_success是否完全成功
     */
    public JSONObject autoAplipayPartyimportBills(String filePath, String hospitalId, String hospitalName, String appId) {
        List<PaymentCheckSourceFile> sourceList = null;
        JSONObject mapReturn = new JSONObject();
        mapReturn.put("hospital_name", hospitalName);
        mapReturn.put("hospital_id", hospitalId);
        mapReturn.put("app_id", appId);
        mapReturn.put("file_path", filePath);
        mapReturn.put("stop_finance_flag", false);
        boolean importFullSuccess = false;//数据是否全部读取完成
        sourceList = new ArrayList();
        try {
            AlipayCSVFileUtil alipayCSVFileUtil = new AlipayCSVFileUtil(filePath);
            List<List<String>> csvDatas = alipayCSVFileUtil.alipayReadCSVFile();
            long beginTime = new Date().getTime() / 1000;
            logger.info("<<<<< aplipayPartyimportBills.beginTime:" + beginTime);

            for (List<String> datas : csvDatas) {

                //过滤非正常交易状态
                if ("退款".equals(datas.get(2)) || "交易".equals(datas.get(2))) {

                    PaymentCheckSourceFile paymentCheckSourceFile = new PaymentCheckSourceFile();

                    paymentCheckSourceFile.setOrgId(hospitalId);
                    paymentCheckSourceFile.setOrgName(hospitalName);
                    paymentCheckSourceFile.setId(UUIDUtil.get32UUID());
                    paymentCheckSourceFile.setPayAppId(appId);
                    paymentCheckSourceFile.setPaymentDealId(datas.get(0));
                    paymentCheckSourceFile.setOrderNo(datas.get(1));
                    paymentCheckSourceFile.setPayStatus(parsePayStatus(datas.get(2)));
                    paymentCheckSourceFile.setPayStatusDesc(datas.get(2));
                    paymentCheckSourceFile.setGoodsName(datas.get(3));
                    paymentCheckSourceFile.setCreatedTime(StringUtils.isBlank(datas.get(4)) ? null : datas.get(4));
                    paymentCheckSourceFile.setPayTime(StringUtils.isBlank(datas.get(5)) ? null : datas.get(5));
                    paymentCheckSourceFile.setAccountName(datas.get(10));
                    paymentCheckSourceFile.setPayAmount(parseAmount(datas.get(12)));
                    paymentCheckSourceFile.setServiceFee(parseAmount(datas.get(22)));
                    paymentCheckSourceFile.setDescription("0.00".equals(datas.get(datas.size() - 1)) ? null : datas.get(datas.size() - 1));
                    paymentCheckSourceFile.setPayMode((short) 2);
                    paymentCheckSourceFile.setImportTime(YYYYMMDDHHMISS.format(new Date()));
                    paymentCheckSourceFile.setUpdateTime(YYYYMMDDHHMISS.format(new Date()));

                    sourceList.add(paymentCheckSourceFile);
                }
            }
            logger.info("<<<<< aplipayPartyimportBills.endTime:" + ((new Date().getTime() / 1000) - beginTime));
            importFullSuccess = true;
        } 
        catch (Exception e) {
			importFullSuccess = false;
			logger.error("autoAplipayPartyimportBills:[第三方账单读取失败]", e);
			mapReturn.put("exception_flag", true);
		}
        mapReturn.put("import_full_success", importFullSuccess);
        mapReturn.put("list", sourceList);
        return mapReturn;
    }

    /**
     * 解析交易状态
     *
     * @param payStatus
     * @return
     */
    public Short parsePayStatus(String payStatus) {
        int ps = 0;
        if ("交易".equals(payStatus)) {
            ps = 1;
        } else if ("退款".equals(payStatus)) {
            ps = 2;
        }
        return (short) ps;
    }


    /**
     * 解析金额
     *
     * @param amount
     * @return
     */
    public int parseAmount(String amount) {
        if (amount.contains("-")) {
            amount = amount.trim().replace("-", "");
        }

        BigDecimal bigDecimal = new BigDecimal(amount);
        BigDecimal multiply = bigDecimal.multiply(new BigDecimal(100));
        return multiply.intValue();
    }


    /**
     * 账单入库
     *
     * @param sourceFiles
     * @return
     */
    public int addSourceFile(List<PaymentCheckSourceFile> sourceFiles, String hospitalId) {
        int count = 0;
        if (sourceFiles.size() > 0) {
            List<PaymentCheckSourceFile> checkList = new ArrayList<PaymentCheckSourceFile>();
//            PaymentCheckSourceFile sourceFile = new PaymentCheckSourceFile();
            try {
                long exbeginTime = new Date().getTime() / 1000;
                logger.info("<<<<< batchInsert.beginTime:" + exbeginTime);
                if (sourceFiles.size() > 0) {
                    paymentCheckSourceFileDao.batchInsert(sourceFiles);
                }
                logger.info("<<<<< batchInsert.endTime:" + (new Date().getTime() / 1000 - exbeginTime));
                count = sourceFiles.size();
            } catch (Exception e) {
                logger.error("保存数据失败", e);
            }
        }
        logger.info("成功入库的记录数："+count);
        return count;
    }


    public static void main(String[] args) {

        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        Calendar cal = Calendar.getInstance();
        cal.setTime(new Date());
        cal.add(Calendar.DAY_OF_MONTH, -1);
        System.out.println(format.format(cal.getTime()));


    }

}
